Skip to content

Feat/crystals+anchors#31

Open
HashimTheArab wants to merge 34 commits into
HashimTheArab:masterfrom
cqdetdev:feat/crystals+anchors
Open

Feat/crystals+anchors#31
HashimTheArab wants to merge 34 commits into
HashimTheArab:masterfrom
cqdetdev:feat/crystals+anchors

Conversation

@HashimTheArab

@HashimTheArab HashimTheArab commented May 24, 2026

Copy link
Copy Markdown
Owner

Note

High Risk
Changes player spawn persistence and cross-dimension respawn resolution, plus End crystal explosions and entity damage paths—core gameplay and world data behavior.

Overview
Adds End crystal placement item/entity behavior (End fire, beam/base metadata, vanilla-style explosions with optional block clipping below obsidian/bedrock and reduced entity damage underwater) and respawn anchors (glowstone charging, Nether spawn setting, charge depletion on respawn, overworld misuse explosion).

Player respawn now stores position + dimension (PlayerSpawn), persists SpawnDimension in LevelDB, and resolves saved spawns via optional WorldByDimension on login/respawn; beds and anchors share a generic respawnBlock safe-spawn path.

Also ships bamboo block/mosaic (separate from log/wood registration), bone meal outcomes (BoneMealResult) driving small vs area particles (including grass spreading plants), HurtEntity so projectiles/melee can damage non-Living entities like crystals, explosion DisableEntityDamage, ray BBoxIntersects/BlockIntersects, chunk clone APIs and HighestFilledSubChunk semantics fix, Sulfur Caves biome, extra debug primitive shapes, and dependency bumps (gophertunnel 1.57, worldupgrader 1.0.21).

Reviewed by Cursor Bugbot for commit 556a712. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Added bamboo block variants, bamboo mosaic blocks, respawn anchors, end crystals, and a new sulfur caves biome.
    • Added support for piercing arrows and new debug shape types.
    • Bone meal now reports richer results for different plants and blocks.
  • Bug Fixes

    • Improved respawn point handling, including dimension-aware spawn saves and respawn anchors.
    • Fixed damage handling for more entity types.
    • Added clearer sound, particle, and metadata updates for newer block and entity interactions.

cqdetdev and others added 14 commits May 9, 2026 13:55
- Implement end crystals as behavior
- Add EndCrystal to explosion config
Constraint: PR df-mc#1247 had merge conflicts against upstream/master in block registration, projectile behavior, and sound declarations.
Rejected: Dropping upstream redstone/piercing changes | conflict resolution must preserve current base behavior.
Confidence: high
Scope-risk: moderate
Directive: Keep projectile piercing collision tracking and non-living damageable entities in sync when editing ProjectileBehaviour.
Tested: go test ./...; git diff --check
Not-tested: In-game Bedrock client interaction.
End crystal placement and damage behavior needed source-backed parity before PR df-mc#1247 could be reviewed cleanly. This keeps the fixes isolated from the upstream merge already pushed to the contributor branch.

Constraint: Primary source guidance came from ../AGENTS.md: Minecraft Wiki and mcsrc.dev first, with Dragonfly conventions preserved where code patterns already existed.
Rejected: Keeping duplicate non-living damage helpers | player and projectile paths both need the same Behaviour-backed damage semantics.
Confidence: high
Scope-risk: moderate
Directive: Keep End crystal zero-damage, explosion-damage, placement-fire, and continuous-End-fire behavior covered when changing entity or item placement paths.
Tested: go test ./...
Not-tested: Live Bedrock client interaction; dedicated regression tests per requester direction.
…fixes

Fix source-backed crystal and anchor parity issues
Constraint: PR df-mc#1247 had already merged before this review cleanup, so this follow-up keeps the change limited to the offset declaration.
Rejected: Keeping generated offset initialization | the explicit priority table is clearer and avoids an init-time helper for fixed vanilla order.
Confidence: high
Scope-risk: narrow
Directive: Preserve the column layer-1/layer-2 priority before layer 3 when editing respawn anchor spawn offsets.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client respawn flow.
Constraint: PR df-mc#1247 follow-up review requested documentation for helper tables and questioned whether a missing End crystal beam target should serialize as 0,0,0.
Rejected: Sending a zero BlockTarget for crystals without a beam target | zero is a concrete position and can be interpreted as a beam target.
Confidence: high
Scope-risk: narrow
Directive: Omit EntityDataKeyBlockTarget unless an End crystal has an explicit beam target.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client metadata rendering.
Constraint: PR df-mc#1247 follow-up review requested documentation for helper tables and questioned whether a missing End crystal beam target should serialize as 0,0,0.
Rejected: Sending a zero BlockTarget for crystals without a beam target | zero is a concrete position and can be interpreted as a beam target.
Confidence: high
Scope-risk: narrow
Directive: Omit EntityDataKeyBlockTarget unless an End crystal has an explicit beam target.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client metadata rendering.
Constraint: Follow-up PR review requested clarity on HurtEntity return values without changing behavior.
Rejected: Adding explicit ProjectileDamageSource ExplodesEndCrystal true | End crystal explosion behavior is opt-out by default, so explicit true methods add noise.
Confidence: high
Scope-risk: narrow
Directive: Keep HurtEntity return tuple semantics aligned with Living.Hurt plus the damageable ok flag.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client interaction.
Constraint: Respawn anchors and beds share the same safe-spawn contract in player respawn logic.
Rejected: Keeping the anonymous inline interface | It obscures the reusable local contract and makes the respawn path harder to scan.
Confidence: high
Scope-risk: narrow
Directive: Keep this interface private unless a non-player package needs to refer to the contract directly.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client respawn interaction.
Constraint: Bedrock lang sources keep tile.bed.notValid scoped to bed wording while respawn anchors have their own notValid key.
Rejected: Java-style combined bed and anchor fallback | It does not match Dragonfly's original fallback or current Bedrock sample text.
Confidence: high
Scope-risk: narrow
Directive: Keep chat translation fallbacks aligned with Bedrock language keys, not wiki prose when they differ.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client locale rendering.
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds End Crystal entities/items, Respawn Anchor blocks with dimension-aware player spawn persistence, Bamboo wood block variants, a graded BoneMealResult enum replacing boolean bone-meal returns across crop blocks, projectile piercing with a generalized HurtEntity abstraction, plus debug shapes, chunk/palette cloning, and assorted fixes.

Changes

End Crystal Entity and Item

Layer / File(s) Summary
Entity type and registration
server/entity/end_crystal.go, server/entity/register.go
Adds EndCrystalType, NewEndCrystal spawner, NBT decode/encode for ShowBottom/BeamTarget, and registers the entity.
Behaviour, damage, and metadata
server/entity/end_crystal_behaviour.go, server/session/entity_metadata.go
Implements fire, Hurt/Explode closing and triggering explosion, and session metadata encoding with a nil-safe UUID check.
Item and placement
server/item/end_crystal.go, server/item/register.go
Adds placement validation (obsidian/bedrock, clear air, no entity intersection), spawns entity, registers item.

Respawn Anchor Block and Dimension-Aware Player Spawn

Layer / File(s) Summary
Block, trace helpers, registration
server/block/respawn_anchor.go, server/block/cube/trace/bbox.go, server/block/cube/trace/block.go, server/block/hash.go, server/block/register.go
Adds RespawnAnchor activation/charging/safe-spawn logic using new BBoxIntersects/BlockIntersects helpers, plus hashing and registration.
Player spawn dimension persistence
server/block/bed.go, server/player/chat/translate.go, server/world/sound/block.go, server/session/world.go, server/player/conf.go, server/player/player.go, server/server.go, server/world/provider.go, server/world/world.go, server/world/mcdb/db.go
Threads WorldByDimension resolver, generalizes respawn resolution via respawnBlock, and persists PlayerSpawn (position + dimension).

Bamboo Wood Blocks

Layer / File(s) Summary
Block definitions
server/block/bamboo_block.go, server/block/bamboo_mosaic.go, server/block/wood_type.go, server/block/hash.go
Adds BambooBlock/BambooMosaic types and BambooWood WoodType.
Registration and wiring
server/block/register.go, server/block/log.go, server/block/wood.go, server/block/slab.go, server/block/slab_type.go, server/block/stairs.go, server/block/stairs_type.go
Registers bamboo blocks/items, excludes BambooWood from generic loops, wires BambooMosaic into slab/stairs.

BoneMealResult Refactor

Layer / File(s) Summary
Core enum and particle
server/item/bone_meal.go, server/world/particle/block.go, server/session/world.go
Introduces BoneMealResult enum, updates interface/UseOnBlock branching, adds Area to BoneMeal particle.
Block implementations
server/block/beetroot_seeds.go, carrot.go, cocoa_bean.go, double_flower.go, fern.go, flower.go, grass.go, kelp.go, melon_seeds.go, pink_petals.go, potato.go, pumpkin_seeds.go, sea_pickle.go, short_grass.go, sugar_cane.go, wheat_seeds.go
Converts all crop/plant BoneMeal methods from bool to BoneMealResult.

Projectile Piercing and Generalized Entity Damage

Layer / File(s) Summary
ArrowSpawnConfig
server/world/entity.go, server/entity/register.go
Introduces ArrowSpawnConfig with PiercingLevel and updates the Arrow spawn handler.
Piercing collision & chargeable
server/entity/projectile.go, server/item/crossbow.go, server/item/item.go, server/player/player.go
Tracks collided entities, closes projectile past PiercingLevel, adds CanCharge and extended Consumer/Chargeable interfaces.
Damage abstraction
server/entity/damageable.go, server/player/player.go
Adds HurtEntity/damageableEntity helpers used by AttackEntity for non-Living targets.

Debug Shapes, Chunk Cloning, and Misc

Layer / File(s) Summary
Debug shapes
server/player/debug/shape.go, server/session/player.go
Adds Cylinder, Pyramid, Ellipsoid, Cone shapes and protocol encoding.
Chunk/palette cloning
server/world/chunk/*.go
Adds Clone methods across Chunk, SubChunk, PalettedStorage, Palette, and RuntimeIDToHash interface method.
Misc fixes
go.mod, server/player/bossbar/colour.go, server/session/enchantment_texts.go, server/session/session.go, server/session/text.go, server/world/mcdb/leveldat/*.go, server/world/biome/*.go
Dependency bumps, colour rename, Nop logger, sound/level.dat fixes, SulfurCaves biome.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Player
  participant World
  participant Provider
  participant DB
  Player->>World: SetPlayerSpawn(pos)
  World->>Provider: SavePlayerSpawn(PlayerSpawn{Pos, Dim})
  Provider->>DB: SavePlayerSpawn(id, spawn)
  Player->>World: PlayerSpawnPoint(id)
  World->>Provider: LoadPlayerSpawn(id)
  Provider->>DB: LoadPlayerSpawn(id)
  DB-->>World: PlayerSpawn{Pos, Dim}
  World-->>Player: spawn, ok
Loading
sequenceDiagram
  participant Projectile
  participant Entity
  participant HurtEntity
  Projectile->>Entity: trace hit (ignoring collided entities)
  Projectile->>HurtEntity: HurtEntity(entity, damage, source)
  HurtEntity-->>Projectile: n, vulnerable, ok
  Projectile->>Projectile: record entity in collidedEntities
  alt collided count > PiercingLevel
    Projectile->>Projectile: close entity
  else
    Projectile->>Projectile: continue flight
  end
Loading

Related PRs: None identified.

Suggested labels: enhancement, feature, refactor

Suggested reviewers: None identified.

🐰 A crystal hums with End-lit fire,
An anchor charges, hearts aspire,
Bamboo sways in gentle breeze,
Bone meal blooms through petaled trees,
Arrows pierce and carry higher.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is directly related to the main change set, highlighting crystals and anchors, which are the core features added.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6f5385b. Configure here.

Comment thread server/entity/end_crystal_behaviour.go Outdated
Comment thread server/player/player.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/entity/projectile.go`:
- Around line 179-183: The collision bookkeeping and hit handling are
incorrectly gated on lt.conf.Damage >= 0 which prevents non-damaging projectiles
from registering hits; remove the Damage >= 0 guard so that
lt.hitEntity(r.Entity(), e, vel) is called on entity collision for all
projectiles and ensure lt.collidedEntities = append(lt.collidedEntities,
r.Entity().H()) is executed when damageableEntity(r.Entity()) is true regardless
of lt.conf.Damage; apply the same change to the other similar blocks that
reference lt.conf.Damage, lt.hitEntity, lt.collidedEntities, and
damageableEntity so collisions are always recorded even for negative-damage
configs.

In `@server/entity/register.go`:
- Around line 52-56: The Arrow spawn function currently does an unchecked type
assertion tip := arrow.Tip.(potion.Potion) and directly calls arrow.Owner.H(),
which can panic if Tip is nil/unset or Owner is nil; update the Arrow function
to defensively check arrow.Tip's type (use a type assertion with ok or a nil
check) before assigning to tip and fall back to a safe default potion or leave
conf.Potion unset, and also validate arrow.Owner is non-nil before calling
arrow.Owner.H() (or use a safe owner handle getter); ensure you still set
conf.Damage, conf.KnockBackForceAddend, and other fields only after these checks
so spawn-time panics are prevented.

In `@server/player/player.go`:
- Around line 1793-1803: The branch for non-living entities returns before the
item's durability is updated; when entity.HurtEntity(e, i.AttackDamage(), ...)
succeeds you must invoke the same durability-wear logic used for living targets
before returning true. Modify the non-living branch (the block using
entity.HurtEntity, p.tx.PlaySound and p.Exhaust) to call the existing
item-durability handler/mutation that the living-target path uses (i.e., the
same code that updates the item stack and triggers break/consume) so durable
items are decremented on successful hits against non-living entities as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cf686165-893e-4c43-90d8-aaab341ed2a3

📥 Commits

Reviewing files that changed from the base of the PR and between ff14ddc and 6f5385b.

📒 Files selected for processing (30)
  • server/block/blast_furnace.go
  • server/block/explosion.go
  • server/block/furnace.go
  • server/block/hash.go
  • server/block/register.go
  • server/block/respawn_anchor.go
  • server/block/smoker.go
  • server/entity/damage.go
  • server/entity/damageable.go
  • server/entity/end_crystal.go
  • server/entity/end_crystal_behaviour.go
  • server/entity/projectile.go
  • server/entity/register.go
  • server/item/bow.go
  • server/item/crossbow.go
  • server/item/enchantment/multishot.go
  • server/item/enchantment/piercing.go
  • server/item/enchantment/register.go
  • server/item/end_crystal.go
  • server/item/golden_apple.go
  • server/item/item.go
  • server/item/register.go
  • server/item/stack.go
  • server/player/chat/translate.go
  • server/player/player.go
  • server/session/entity_metadata.go
  • server/session/world.go
  • server/world/block_registry.go
  • server/world/entity.go
  • server/world/sound/block.go

Comment thread server/entity/projectile.go Outdated
Comment on lines +179 to +183
if lt.conf.Damage >= 0 {
lt.hitEntity(r.Entity(), e, vel)
if damageableEntity(r.Entity()) {
lt.collidedEntities = append(lt.collidedEntities, r.Entity().H())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Non-damaging projectiles no longer terminate on entity collision

Line 179 gates collision bookkeeping behind Damage >= 0, but Line 200 closes using collidedEntities length. For configs using negative damage, hits are never counted, so the projectile never closes after entity impact (and with Line 333 it can just stop moving in-place).

🔧 Proposed fix
 	switch r := result.(type) {
 	case trace.EntityResult:
-		if lt.conf.Damage >= 0 {
-			lt.hitEntity(r.Entity(), e, vel)
-			if damageableEntity(r.Entity()) {
-				lt.collidedEntities = append(lt.collidedEntities, r.Entity().H())
-			}
-		}
+		if damageableEntity(r.Entity()) {
+			if lt.conf.Damage >= 0 {
+				lt.hitEntity(r.Entity(), e, vel)
+			}
+			lt.collidedEntities = append(lt.collidedEntities, r.Entity().H())
+		}

Also applies to: 200-202, 333-335

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/entity/projectile.go` around lines 179 - 183, The collision
bookkeeping and hit handling are incorrectly gated on lt.conf.Damage >= 0 which
prevents non-damaging projectiles from registering hits; remove the Damage >= 0
guard so that lt.hitEntity(r.Entity(), e, vel) is called on entity collision for
all projectiles and ensure lt.collidedEntities = append(lt.collidedEntities,
r.Entity().H()) is executed when damageableEntity(r.Entity()) is true regardless
of lt.conf.Damage; apply the same change to the other similar blocks that
reference lt.conf.Damage, lt.hitEntity, lt.collidedEntities, and
damageableEntity so collisions are always recorded even for negative-damage
configs.

Comment thread server/entity/register.go
Comment on lines +52 to +56
Arrow: func(opts world.EntitySpawnOpts, arrow world.ArrowSpawnConfig) *world.EntityHandle {
tip := arrow.Tip.(potion.Potion)
conf := arrowConf
conf.Damage, conf.Potion, conf.Owner = damage, tip.(potion.Potion), owner.H()
conf.KnockBackForceAddend = float64(punchLevel) * enchantment.Punch.KnockBackMultiplier()
conf.DisablePickup = disallowPickup
if obtainArrowOnPickup {
conf.PickupItem = item.NewStack(item.Arrow{Tip: tip.(potion.Potion)}, 1)
conf.Damage, conf.Potion, conf.Owner = arrow.Damage, tip, arrow.Owner.H()
conf.KnockBackForceAddend = float64(arrow.PunchLevel) * enchantment.Punch.KnockBackMultiplier()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all ArrowSpawnConfig callsites and whether Tip/Owner are always set.
fd -e go | xargs rg -nP 'ArrowSpawnConfig\s*{' -C3
fd -e go | xargs rg -nP 'EntityRegistry\(\)\.Config\(\)\.Arrow\s*\(' -C3

Repository: HashimTheArab/dragonfly

Length of output: 822


Defensively handle world.ArrowSpawnConfig fields to avoid spawn-time panics.

server/entity/register.go does tip := arrow.Tip.(potion.Potion), but server/item/crossbow.go constructs world.ArrowSpawnConfig{...} without setting Tip, so this can panic when spawning arrows. Guard the type assertion (and arrow.Owner.H() for safety).

💡 Suggested hardening
 Arrow: func(opts world.EntitySpawnOpts, arrow world.ArrowSpawnConfig) *world.EntityHandle {
-	tip := arrow.Tip.(potion.Potion)
+	tip, _ := arrow.Tip.(potion.Potion)
 	conf := arrowConf
-	conf.Damage, conf.Potion, conf.Owner = arrow.Damage, tip, arrow.Owner.H()
+	conf.Damage, conf.Potion = arrow.Damage, tip
+	if arrow.Owner != nil {
+		conf.Owner = arrow.Owner.H()
+	}
 	conf.KnockBackForceAddend = float64(arrow.PunchLevel) * enchantment.Punch.KnockBackMultiplier()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Arrow: func(opts world.EntitySpawnOpts, arrow world.ArrowSpawnConfig) *world.EntityHandle {
tip := arrow.Tip.(potion.Potion)
conf := arrowConf
conf.Damage, conf.Potion, conf.Owner = damage, tip.(potion.Potion), owner.H()
conf.KnockBackForceAddend = float64(punchLevel) * enchantment.Punch.KnockBackMultiplier()
conf.DisablePickup = disallowPickup
if obtainArrowOnPickup {
conf.PickupItem = item.NewStack(item.Arrow{Tip: tip.(potion.Potion)}, 1)
conf.Damage, conf.Potion, conf.Owner = arrow.Damage, tip, arrow.Owner.H()
conf.KnockBackForceAddend = float64(arrow.PunchLevel) * enchantment.Punch.KnockBackMultiplier()
Arrow: func(opts world.EntitySpawnOpts, arrow world.ArrowSpawnConfig) *world.EntityHandle {
tip, _ := arrow.Tip.(potion.Potion)
conf := arrowConf
conf.Damage, conf.Potion = arrow.Damage, tip
if arrow.Owner != nil {
conf.Owner = arrow.Owner.H()
}
conf.KnockBackForceAddend = float64(arrow.PunchLevel) * enchantment.Punch.KnockBackMultiplier()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/entity/register.go` around lines 52 - 56, The Arrow spawn function
currently does an unchecked type assertion tip := arrow.Tip.(potion.Potion) and
directly calls arrow.Owner.H(), which can panic if Tip is nil/unset or Owner is
nil; update the Arrow function to defensively check arrow.Tip's type (use a type
assertion with ok or a nil check) before assigning to tip and fall back to a
safe default potion or leave conf.Potion unset, and also validate arrow.Owner is
non-nil before calling arrow.Owner.H() (or use a safe owner handle getter);
ensure you still set conf.Damage, conf.KnockBackForceAddend, and other fields
only after these checks so spawn-time panics are prevented.

Comment thread server/player/player.go
Comment on lines 1793 to 1803
if !isLiving {
return false
n, vulnerable, ok := entity.HurtEntity(e, i.AttackDamage(), entity.AttackDamageSource{Attacker: p})
if !ok {
return false
}
p.tx.PlaySound(entity.EyePosition(e), sound.Attack{Damage: !mgl64.FloatEqual(n, 0)})
if vulnerable {
p.Exhaust(0.1)
}
return true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Durability isn’t consumed when attacking non-living entities.

This new branch returns before the durability logic, so durable items never wear when damaging non-living targets.

Proposed fix
 	if !isLiving {
 		n, vulnerable, ok := entity.HurtEntity(e, i.AttackDamage(), entity.AttackDamageSource{Attacker: p})
 		if !ok {
 			return false
 		}
+		if durable, ok := i.Item().(item.Durable); ok {
+			_, left := p.HeldItems()
+			p.SetHeldItems(p.damageItem(i, durable.DurabilityInfo().AttackDurability), left)
+		}
 		p.tx.PlaySound(entity.EyePosition(e), sound.Attack{Damage: !mgl64.FloatEqual(n, 0)})
 		if vulnerable {
 			p.Exhaust(0.1)
 		}
 		return true
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/player/player.go` around lines 1793 - 1803, The branch for non-living
entities returns before the item's durability is updated; when
entity.HurtEntity(e, i.AttackDamage(), ...) succeeds you must invoke the same
durability-wear logic used for living targets before returning true. Modify the
non-living branch (the block using entity.HurtEntity, p.tx.PlaySound and
p.Exhaust) to call the existing item-durability handler/mutation that the
living-target path uses (i.e., the same code that updates the item stack and
triggers break/consume) so durable items are decremented on successful hits
against non-living entities as well.

HashimTheArab and others added 13 commits May 24, 2026 20:13
Constraint: Respawn anchors must resolve in their saved dimension, End crystal placement checks the two-block column above the base, End crystal block clipping is source-backed only for supported crystals, and water must suppress End crystal entity impact.
Rejected: Keeping position-only player spawn provider methods | Spawn position without dimension cannot model Bedrock's saved respawn target once anchors are supported.
Confidence: medium
Scope-risk: moderate
Directive: Keep player spawn dimension persistence aligned with Bedrock player data and do not reapply End crystal Y clipping to entity exposure without a primary source.
Tested: go test ./...; git diff --check
Not-tested: Live Bedrock client respawn across dimensions; in-game End crystal water neutralization.
Fix respawn and End crystal parity gaps
…player has no suitable item to insert projectile into it (df-mc#1272)

* crossbow.go: Fix crossbow charging animation played even if the player has no suitable item to insert suitable projectile into it

* crossbow.go: use blank identifier for unused "tx" variable
…mc#1278)

* fix(session): guard nil session handle in metadata

* fix(session): guard nil entity handles in session helpers

* Update session_list.go

* various changes

* Update session.go
smell-of-curry and others added 6 commits June 24, 2026 12:04
* Implement bamboo building set

* Order bamboo item registrations

* Improve documentation for allWood function

Updated the allWood function documentation to clarify that bamboo blocks are registered separately.

* avoid duplicate bamboo block properties
@cursor

cursor Bot commented Jul 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_9afaf66c-c28f-49ea-911b-bab5c9e10a1e)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
server/block/sugar_cane.go (1)

67-80: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return BoneMealResultNone when no sugar cane block is placed.
canGrowHere only checks the base conditions, so a max-height cane stack still reports BoneMealResultSmall even though the loop doesn't add anything. That makes bone meal get consumed and the growth particle play on a no-op.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/block/sugar_cane.go` around lines 67 - 80, Update SugarCane.BoneMeal
so it only returns BoneMealResultSmall when at least one SugarCane block is
actually placed. After the canGrowHere check and placement loop, track whether
any Air block was replaced via tx.SetBlock, and return BoneMealResultNone when
the loop makes no changes (for example, a max-height stack). Keep the existing
logic in SugarCane.BoneMeal and canGrowHere, but gate the success result on an
actual placement.
server/block/sea_pickle.go (1)

45-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return BoneMealResultArea for sea pickle spread.
This loop places pickles across a multi-block area, so Small underreports the effect and triggers the smaller particle burst.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/block/sea_pickle.go` around lines 45 - 78, Update SeaPickle.BoneMeal
to return item.BoneMealResultArea instead of item.BoneMealResultSmall when the
spread loop succeeds, since this method is placing new SeaPickle blocks across
multiple positions and should report an area effect; keep the existing placement
logic and only change the final result returned from BoneMeal.
server/block/respawn_anchor.go (1)

137-156: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Candidate spawn positions aren't checked for lava/water.

respawnAnchorSpawnClear only rejects a position when a block's model bbox overlaps the 2‑block column; liquids typically have empty collision models, so lava/water at a candidate position won't be detected as an obstruction. Vanilla explicitly treats liquids as obstructing: if the area around it is unsuitable for respawning (i.e Lava surrounding it), a message is displayed reading "You have no home bed or charged respawn anchor, or it was obstructed". Bed.Activate already guards against this with an explicit tx.Liquid(headPos) check, but that check isn't mirrored here for anchor candidates.

🛡️ Proposed fix
 	occupied := cube.Box(0, 0, 0, 1, 2, 1).Translate(pos.Vec3())
 	for y := 0; y < 2; y++ {
 		blockPos := pos.Add(cube.Pos{0, y})
+		if _, ok := tx.Liquid(blockPos); ok {
+			return false
+		}
 		for _, box := range tx.Block(blockPos).Model().BBox(blockPos, tx) {
 			if box.Translate(blockPos.Vec3()).IntersectsWith(occupied) {
 				return false
 			}
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/block/respawn_anchor.go` around lines 137 - 156,
respawnAnchorSpawnClear currently only checks block collision boxes, so liquid
blocks like lava or water can still be treated as valid spawn spaces. Update
this function to also reject candidate positions when either the target block or
the block above contains liquid, using the existing world liquid lookup on tx
for the checked positions. Keep the existing bounds and solid-support checks,
and make the new liquid obstruction check part of the same respawn clearance
logic in respawnAnchorSpawnClear so it matches Bed.Activate behavior.
🧹 Nitpick comments (4)
server/item/end_crystal.go (2)

25-27: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Placement only allows strict air, not other replaceable blocks.

Vanilla allows placement if the two blocks above the bedrock or obsidian block are air or replaceable blocks and no other entities intersect the area. This implementation only permits exact air, rejecting placement over e.g. short grass, snow layers, or non-solid replaceable vegetation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/item/end_crystal.go` around lines 25 - 27, The placement check in
EndCrystal placement is too strict because it only accepts exact air for the two
blocks above the base block. Update the logic in the EndCrystal placement path
to use the same replaceable-block check as vanilla, allowing air or other
replaceable blocks (such as grass, snow layers, or vegetation) while still
rejecting non-replaceable blocks and respecting entity collision checks.

16-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer type assertion over string comparison for base-block validation.

Using EncodeBlock() string comparison works, but a type assertion (e.g. _, obsidian := tx.Block(pos).(block.Obsidian)) is more idiomatic here and avoids depending on the exact NBT/name-encoding format, consistent with block-type checks used elsewhere in the codebase (e.g. RespawnAnchor.Activate's held.Item().(Glowstone)).

♻️ Suggested refactor
-	clickedBlock, _ := tx.Block(pos).EncodeBlock()
-	if clickedBlock != "minecraft:obsidian" && clickedBlock != "minecraft:bedrock" {
+	switch tx.Block(pos).(type) {
+	case Obsidian, Bedrock:
+	default:
 		return false
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/item/end_crystal.go` around lines 16 - 19, The base-block check in the
crystal placement logic is using EncodeBlock string comparisons instead of a
block type check. Update the validation in the end crystal handler to use type
assertions on tx.Block(pos), matching the style used elsewhere such as
RespawnAnchor.Activate and other block-specific checks, and accept only the
Obsidian/Bedrock block types rather than relying on encoded names.
server/block/carrot.go (1)

41-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider consolidating duplicated growth-bonemeal logic.

The BoneMeal implementation here is structurally identical to Potato.BoneMeal (server/block/potato.go) and WheatSeeds.BoneMeal (server/block/wheat_seeds.go) — only the receiver type differs. A small shared helper (e.g. on the embedded crop type, taking the concrete block as a parameter) could remove this triplication now that all three were touched in this refactor.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/block/carrot.go` around lines 41 - 47, The BoneMeal logic in Carrot is
duplicated across Carrot.BoneMeal, Potato.BoneMeal, and WheatSeeds.BoneMeal;
extract the shared growth-and-set behavior into a common helper on the embedded
crop type or a small shared function. Update the Carrot, Potato, and WheatSeeds
implementations to call that helper with the concrete block receiver so the
growth update, tx.SetBlock call, and BoneMealResult handling stay identical in
one place.
server/player/player.go (1)

949-1003: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicated portal-destination fallback computation.

fallback := p.tx.World().PortalDestination(p.tx.World().Dimension()) re-implements the same "round-trip portal" pattern already used inside spawnLocation()'s no-spawn-point branch (w = w.PortalDestination(w.Dimension())). Consider extracting a small helper (e.g. overworldFallback(w *world.World) *world.World) shared by both call sites to avoid the two places drifting apart later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/player/player.go` around lines 949 - 1003, The respawn flow duplicates
the portal-destination fallback logic already present in spawnLocation(), which
can drift over time. Extract the shared world fallback calculation into a small
helper such as overworldFallback and use it both in Player.respawn and
spawnLocation()’s no-spawn-point branch. Keep the helper centered around
PortalDestination and Dimension so both call sites stay consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/item/crossbow.go`:
- Around line 158-162: The Crossbow charging check in CanCharge is using the
wrong item state, so the charging path never starts after Player.UseItem falls
back from ReleaseCharge. Update CanCharge in Crossbow to require the crossbow to
be empty instead of non-empty, while still keeping the projectile lookup via
findProjectile and the found check.

In `@server/world/mcdb/db.go`:
- Around line 75-79: The spawn coordinate loading in the db.go path is using
unsafe type assertions for SpawnX, SpawnY, and SpawnZ, so malformed server data
can panic. Update the spawn parsing logic around the existing serverData lookup
and PlayerSpawn construction to use guarded comma-ok assertions, matching the
safer SpawnDimension handling already used nearby, and return the same error
path if any coordinate is missing or not int32.

---

Outside diff comments:
In `@server/block/respawn_anchor.go`:
- Around line 137-156: respawnAnchorSpawnClear currently only checks block
collision boxes, so liquid blocks like lava or water can still be treated as
valid spawn spaces. Update this function to also reject candidate positions when
either the target block or the block above contains liquid, using the existing
world liquid lookup on tx for the checked positions. Keep the existing bounds
and solid-support checks, and make the new liquid obstruction check part of the
same respawn clearance logic in respawnAnchorSpawnClear so it matches
Bed.Activate behavior.

In `@server/block/sea_pickle.go`:
- Around line 45-78: Update SeaPickle.BoneMeal to return item.BoneMealResultArea
instead of item.BoneMealResultSmall when the spread loop succeeds, since this
method is placing new SeaPickle blocks across multiple positions and should
report an area effect; keep the existing placement logic and only change the
final result returned from BoneMeal.

In `@server/block/sugar_cane.go`:
- Around line 67-80: Update SugarCane.BoneMeal so it only returns
BoneMealResultSmall when at least one SugarCane block is actually placed. After
the canGrowHere check and placement loop, track whether any Air block was
replaced via tx.SetBlock, and return BoneMealResultNone when the loop makes no
changes (for example, a max-height stack). Keep the existing logic in
SugarCane.BoneMeal and canGrowHere, but gate the success result on an actual
placement.

---

Nitpick comments:
In `@server/block/carrot.go`:
- Around line 41-47: The BoneMeal logic in Carrot is duplicated across
Carrot.BoneMeal, Potato.BoneMeal, and WheatSeeds.BoneMeal; extract the shared
growth-and-set behavior into a common helper on the embedded crop type or a
small shared function. Update the Carrot, Potato, and WheatSeeds implementations
to call that helper with the concrete block receiver so the growth update,
tx.SetBlock call, and BoneMealResult handling stay identical in one place.

In `@server/item/end_crystal.go`:
- Around line 25-27: The placement check in EndCrystal placement is too strict
because it only accepts exact air for the two blocks above the base block.
Update the logic in the EndCrystal placement path to use the same
replaceable-block check as vanilla, allowing air or other replaceable blocks
(such as grass, snow layers, or vegetation) while still rejecting
non-replaceable blocks and respecting entity collision checks.
- Around line 16-19: The base-block check in the crystal placement logic is
using EncodeBlock string comparisons instead of a block type check. Update the
validation in the end crystal handler to use type assertions on tx.Block(pos),
matching the style used elsewhere such as RespawnAnchor.Activate and other
block-specific checks, and accept only the Obsidian/Bedrock block types rather
than relying on encoded names.

In `@server/player/player.go`:
- Around line 949-1003: The respawn flow duplicates the portal-destination
fallback logic already present in spawnLocation(), which can drift over time.
Extract the shared world fallback calculation into a small helper such as
overworldFallback and use it both in Player.respawn and spawnLocation()’s
no-spawn-point branch. Keep the helper centered around PortalDestination and
Dimension so both call sites stay consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4da33e28-672b-44ed-97e9-b698edd01cae

📥 Commits

Reviewing files that changed from the base of the PR and between 6f5385b and d9f3cf5.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (68)
  • go.mod
  • server/block/bamboo_block.go
  • server/block/bamboo_mosaic.go
  • server/block/bed.go
  • server/block/beetroot_seeds.go
  • server/block/carrot.go
  • server/block/cocoa_bean.go
  • server/block/cube/trace/bbox.go
  • server/block/cube/trace/block.go
  • server/block/double_flower.go
  • server/block/fern.go
  • server/block/flower.go
  • server/block/grass.go
  • server/block/hash.go
  • server/block/kelp.go
  • server/block/log.go
  • server/block/melon_seeds.go
  • server/block/pink_petals.go
  • server/block/potato.go
  • server/block/pumpkin_seeds.go
  • server/block/register.go
  • server/block/respawn_anchor.go
  • server/block/sea_pickle.go
  • server/block/short_grass.go
  • server/block/slab.go
  • server/block/slab_type.go
  • server/block/stairs.go
  • server/block/stairs_type.go
  • server/block/sugar_cane.go
  • server/block/wheat_seeds.go
  • server/block/wood.go
  • server/block/wood_type.go
  • server/entity/end_crystal_behaviour.go
  • server/entity/projectile.go
  • server/item/bone_meal.go
  • server/item/creative/creative_items.nbt
  • server/item/crossbow.go
  • server/item/end_crystal.go
  • server/item/item.go
  • server/item/recipe/crafting_data.nbt
  • server/item/recipe/potion_data.nbt
  • server/player/bossbar/colour.go
  • server/player/chat/translate.go
  • server/player/conf.go
  • server/player/debug/shape.go
  • server/player/player.go
  • server/server.go
  • server/session/enchantment_texts.go
  • server/session/entity_metadata.go
  • server/session/player.go
  • server/session/session.go
  • server/session/text.go
  • server/session/world.go
  • server/world/biome/register.go
  • server/world/biome/sulfur_caves.go
  • server/world/block_states.nbt
  • server/world/chunk/block_registry.go
  • server/world/chunk/chunk.go
  • server/world/chunk/palette.go
  • server/world/chunk/paletted_storage.go
  • server/world/chunk/sub_chunk.go
  • server/world/mcdb/db.go
  • server/world/mcdb/leveldat/data.go
  • server/world/mcdb/leveldat/level_dat.go
  • server/world/particle/block.go
  • server/world/provider.go
  • server/world/vanilla_items.nbt
  • server/world/world.go
✅ Files skipped from review due to trivial changes (2)
  • server/session/enchantment_texts.go
  • server/block/hash.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • server/session/entity_metadata.go
  • server/player/chat/translate.go
  • server/entity/projectile.go

Comment thread server/item/crossbow.go
Comment on lines +158 to +162
// CanCharge ...
func (c Crossbow) CanCharge(releaser Releaser, _ *world.Tx, ctx *UseContext) bool {
_, found := c.findProjectile(releaser, ctx)
return found && !c.Item.Empty()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the crossbow implementation and nearby call sites.
git ls-files server/item/crossbow.go server/** | sed -n '1,120p'
echo '--- crossbow.go ---'
cat -n server/item/crossbow.go | sed -n '1,260p'

echo '--- search ReleaseCharge / CanCharge / UseItem ---'
rg -n "ReleaseCharge|CanCharge|UseItem|findProjectile" server -S

Repository: HashimTheArab/dragonfly

Length of output: 17644


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cat -n server/player/player.go | sed -n '1548,1578p'

Repository: HashimTheArab/dragonfly

Length of output: 1147


Crossbow charging is gated on the wrong item state.

Player.UseItem only reaches CanCharge after ReleaseCharge fails, which means the crossbow is still unloaded there. CanCharge currently requires !c.Item.Empty(), so the charging path never starts. Flip the condition to c.Item.Empty().

🐛 Proposed fix
 func (c Crossbow) CanCharge(releaser Releaser, _ *world.Tx, ctx *UseContext) bool {
 	_, found := c.findProjectile(releaser, ctx)
-	return found && !c.Item.Empty()
+	return found && c.Item.Empty()
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// CanCharge ...
func (c Crossbow) CanCharge(releaser Releaser, _ *world.Tx, ctx *UseContext) bool {
_, found := c.findProjectile(releaser, ctx)
return found && !c.Item.Empty()
}
// CanCharge ...
func (c Crossbow) CanCharge(releaser Releaser, _ *world.Tx, ctx *UseContext) bool {
_, found := c.findProjectile(releaser, ctx)
return found && c.Item.Empty()
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/item/crossbow.go` around lines 158 - 162, The Crossbow charging check
in CanCharge is using the wrong item state, so the charging path never starts
after Player.UseItem falls back from ReleaseCharge. Update CanCharge in Crossbow
to require the crossbow to be empty instead of non-empty, while still keeping
the projectile lookup via findProjectile and the found check.

Comment thread server/world/mcdb/db.go
Comment on lines 75 to +79
x, y, z := serverData["SpawnX"], serverData["SpawnY"], serverData["SpawnZ"]
if x == nil || y == nil || z == nil {
return cube.Pos{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
return world.PlayerSpawn{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
}
return cube.Pos{int(x.(int32)), int(y.(int32)), int(z.(int32))}, true, nil
spawn = world.PlayerSpawn{Pos: cube.Pos{int(x.(int32)), int(y.(int32)), int(z.(int32))}, Dim: world.Overworld}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Unguarded type assertions on SpawnX/Y/Z can panic on malformed data.

x, y, z are checked for nil but not asserted safely; x.(int32) etc. will panic if the stored value isn't int32 (e.g. corrupted or foreign level data). Contrast with the SpawnDimension handling two lines below, which uses the safe comma-ok form. Recommend applying the same guarded pattern here.

🛡️ Proposed fix
-	x, y, z := serverData["SpawnX"], serverData["SpawnY"], serverData["SpawnZ"]
-	if x == nil || y == nil || z == nil {
-		return world.PlayerSpawn{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
-	}
-	spawn = world.PlayerSpawn{Pos: cube.Pos{int(x.(int32)), int(y.(int32)), int(z.(int32))}, Dim: world.Overworld}
+	x, xOk := serverData["SpawnX"].(int32)
+	y, yOk := serverData["SpawnY"].(int32)
+	z, zOk := serverData["SpawnZ"].(int32)
+	if !xOk || !yOk || !zOk {
+		return world.PlayerSpawn{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
+	}
+	spawn = world.PlayerSpawn{Pos: cube.Pos{int(x), int(y), int(z)}, Dim: world.Overworld}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
x, y, z := serverData["SpawnX"], serverData["SpawnY"], serverData["SpawnZ"]
if x == nil || y == nil || z == nil {
return cube.Pos{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
return world.PlayerSpawn{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
}
return cube.Pos{int(x.(int32)), int(y.(int32)), int(z.(int32))}, true, nil
spawn = world.PlayerSpawn{Pos: cube.Pos{int(x.(int32)), int(y.(int32)), int(z.(int32))}, Dim: world.Overworld}
x, xOk := serverData["SpawnX"].(int32)
y, yOk := serverData["SpawnY"].(int32)
z, zOk := serverData["SpawnZ"].(int32)
if !xOk || !yOk || !zOk {
return world.PlayerSpawn{}, true, fmt.Errorf("error reading spawn fields from server data for player %v", id)
}
spawn = world.PlayerSpawn{Pos: cube.Pos{int(x), int(y), int(z)}, Dim: world.Overworld}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/world/mcdb/db.go` around lines 75 - 79, The spawn coordinate loading
in the db.go path is using unsafe type assertions for SpawnX, SpawnY, and
SpawnZ, so malformed server data can panic. Update the spawn parsing logic
around the existing serverData lookup and PlayerSpawn construction to use
guarded comma-ok assertions, matching the safer SpawnDimension handling already
used nearby, and return the same error path if any coordinate is missing or not
int32.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants